package com.hexiang.config;

import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

@Configuration
public class RestTemplatePoolConfig {


    /**
     * 让spring管理RestTemplate,参数相关配置
     *
     * @param builder
     * @return
     */
    @Bean
    public RestTemplate slowRestTemplate(RestTemplateBuilder builder) {
        // 生成一个RestTemplate实例
        RestTemplate restTemplate = builder.build();
        restTemplate.setRequestFactory(slowClientHttpRequestFactory());
        return restTemplate;
    }

//    @Bean
//    public RestTemplate restTemplate(RestTemplateBuilder builder) {
//        // 生成一个RestTemplate实例
//        RestTemplate restTemplate = builder.build();
//        restTemplate.setRequestFactory(fastClientHttpRequestFactory());
//        return restTemplate;
//    }
    @Bean
    public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();

        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext,
                new String[]{"TLSv1"},
                null,
                NoopHostnameVerifier.INSTANCE);

        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();

        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setHttpClient(httpClientBuilder().build());
        // 连接超时时间/毫秒
        clientHttpRequestFactory.setConnectTimeout(2000);
        // 读写超时时间/毫秒
        clientHttpRequestFactory.setReadTimeout(2000);
        // 请求超时时间/毫秒
        clientHttpRequestFactory.setConnectionRequestTimeout(2000);
        clientHttpRequestFactory.setHttpClient(httpClient);
        return new RestTemplate(clientHttpRequestFactory);
    }

    /**
     * 客户端请求链接策略
     *
     * @return
     */
    @Bean
    public ClientHttpRequestFactory slowClientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setHttpClient(httpClientBuilder().build());
        // 连接超时时间/毫秒
        clientHttpRequestFactory.setConnectTimeout(3000);
        // 读写超时时间/毫秒
        clientHttpRequestFactory.setReadTimeout(5000);
        // 请求超时时间/毫秒
        clientHttpRequestFactory.setConnectionRequestTimeout(5000);
        return clientHttpRequestFactory;
    }

    @Bean
    public ClientHttpRequestFactory fastClientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setHttpClient(httpClientBuilder().build());
        // 连接超时时间/毫秒
        clientHttpRequestFactory.setConnectTimeout(2000);
        // 读写超时时间/毫秒
        clientHttpRequestFactory.setReadTimeout(2000);
        // 请求超时时间/毫秒
        clientHttpRequestFactory.setConnectionRequestTimeout(2000);
        return clientHttpRequestFactory;
    }

    /**
     * 设置HTTP连接管理器,连接池相关配置管理
     *
     * @return 客户端链接管理器
     */
    @Bean
    public HttpClientBuilder httpClientBuilder() {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        httpClientBuilder.setConnectionManager(poolingConnectionManager());
        return httpClientBuilder;
    }

    /**
     * 链接线程池管理,可以keep-alive不断开链接请求,这样速度会更快 MaxTotal 连接池最大连接数 DefaultMaxPerRoute
     * 每个主机的并发 ValidateAfterInactivity
     * 可用空闲连接过期时间,重用空闲连接时会先检查是否空闲时间超过这个时间，如果超过，释放socket重新建立
     *
     * @return
     */
    @Bean
    public HttpClientConnectionManager poolingConnectionManager() {
        PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
        //连接池最大的连接数
        poolingConnectionManager.setMaxTotal(50);
        //默认的每个路由上最大的连接数（不能超过连接池总连接数）
        poolingConnectionManager.setDefaultMaxPerRoute(20);
        //空闲永久连接检查间隔，官方推荐使用这个来检查永久链接的可用性，而不推荐每次请求的时候才去检查（ms）
        poolingConnectionManager.setValidateAfterInactivity(2000);
        return poolingConnectionManager;
    }
}